package com.allwees.bs.module.oms.service.impl;

import com.allwees.bs.core.model.order.config.ScheduleTimeProperties;
import com.allwees.bs.core.model.order.wf.order.EOrderAction;
import com.allwees.bs.core.model.order.wf.order.EOrderItemAction;
import com.allwees.bs.core.model.order.wf.order.EOrderItemState;
import com.allwees.bs.core.model.order.wf.refund.ERefundState;
import com.allwees.bs.core.model.payment.enums.EPaymentType;
import com.allwees.bs.module.mms.dao.RetailerDao;
import com.allwees.bs.module.mms.entity.Retailer;
import com.allwees.bs.module.oms.account.runner.AccountTransitUtils;
import com.allwees.bs.module.oms.context.processor.OrderRefundPostProcessor;
import com.allwees.bs.module.oms.dao.OmsOrderDao;
import com.allwees.bs.module.oms.dao.OmsOrderItemDao;
import com.allwees.bs.module.oms.dao.OrderDao;
import com.allwees.bs.module.oms.dao.OrderItemDao;
import com.allwees.bs.module.oms.entity.OmsOrder;
import com.allwees.bs.module.oms.entity.OmsOrderItem;
import com.allwees.bs.module.oms.entity.Order;
import com.allwees.bs.module.oms.entity.OrderItem;
import com.allwees.bs.module.oms.service.GeneralOmsOrderItemService;
import com.allwees.bs.module.oms.service.GeneralOmsOrderService;
import com.allwees.bs.module.oms.service.OmsOrderBatchService;
import com.allwees.bs.module.oms.util.OmsNoUtil;
import com.allwees.bs.module.oms.wf.EOmsOrderAction;
import com.allwees.bs.module.oms.wf.EOmsOrderState;
import com.allwees.bs.module.pms.dao.ProductDao;
import com.allwees.bs.module.pms.dao.SkuDao;
import com.allwees.bs.module.pms.entity.Product;
import com.allwees.core.common.constant.EStatus;
import com.allwees.core.common.util.DateUtil;
import com.allwees.sender.sms.SmsSender;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


@Slf4j
@Service
public class GeneralOmsOrderServiceImpl extends BaseOmsOrderServiceImpl implements GeneralOmsOrderService {

    @Autowired
    protected OrderDao orderDao;
    @Autowired
    protected OrderItemDao orderItemDao;
    @Autowired
    protected OmsOrderBatchService orderBatchService;
    @Autowired
    protected OmsOrderItemDao omsOrderItemDao;

    @Autowired
    protected OmsOrderDao omsOrderDao;

    @Autowired
    private GeneralOmsOrderItemService generalOmsOrderItemService;
    @Autowired
    private ScheduleTimeProperties scheduleTimeProperties;
    @Autowired
    private OrderRefundPostProcessor orderRefundPostProcessor;

    @Autowired
    private ProductDao productDao;

    @Autowired
    private SkuDao skuDao;

    @Autowired
    private RetailerDao retailerDao;

    @Autowired
    private SmsSender smsSender;

    @Autowired
    //private AccountService accountService;
    private AccountTransitUtils accountTransitUtils;


    @Override
    @Transactional
    public void create(String orderUuid) {
        Order order = orderDao.findByUuid(orderUuid);
        Assert.notNull(order, "order[" + orderUuid + "] is null");

        String batchNo = orderBatchService.findCurrentBatchNo();

        OmsOrder omsOrder = order.convertToOmsOrder();
        omsOrder.setBatchNo(batchNo);
        omsOrder.start(EOmsOrderState.START, EOmsOrderAction.SYSTEM_SYNC);
        baseMapper.create(omsOrder);
        Date canShippingAt ;
        if (EPaymentType.COD.equals(order.getPaymentType())) {
            canShippingAt = DateUtil.addSeconds(DateUtil.now(), scheduleTimeProperties.getOrderPayAfterFreezeSecond());
        } else {
            canShippingAt = DateUtil.addSeconds(order.getPaymentAt(), scheduleTimeProperties.getOrderPayAfterFreezeSecond());
        }

        List<OrderItem> orderItems = orderItemDao.selectListByOrderUuid(orderUuid);
        Map<String, BigDecimal> retailerAmtMap = new HashMap<>();
        Date finalCanShippingAt = canShippingAt;
        orderItems.forEach(orderItem -> {
            String productUuid = orderItem.getProductUuid();
            Product product = productDao.findByUuid(productUuid);
            _createOrderItem(batchNo, finalCanShippingAt, order, orderItem, product.getDefNo());
            String retailerUuid = product.getRetailerUuid();
            //BigDecimal retailerTotalAmt = product.getRetailPrice().add(orderItem.getAmtShipping());
            BigDecimal retailerTotalAmt = orderItem.getMerchantAmtSku();
            if (retailerAmtMap.containsKey(retailerUuid)) {
                retailerTotalAmt = retailerAmtMap.get(retailerUuid).add(retailerTotalAmt);
            }
            retailerAmtMap.put(retailerUuid, retailerTotalAmt);
            //accountService.doWaitingShipAmt(orderItem);
            accountTransitUtils.accountTransit(orderItem,"doWaitingShipAmt");
        });

        _synced(orderUuid);

        for (String retailerUuid : retailerAmtMap.keySet()) {
            BigDecimal retailerTotalAmt1 = retailerAmtMap.get(retailerUuid);
            Retailer retailer = retailerDao.findByUuid(retailerUuid);
            String mobile = retailer.getPhone();
            if (StringUtils.isBlank(mobile)) {
                log.warn("Retailer [{}] phone is null", retailer.getCompanyName());
                continue;
            }
            smsSender.confirmAmountSendSms(mobile, retailerTotalAmt1.toString());
        }
    }

    @Override
    @Transactional
    public void doReceived(String orderItemUuid) {
        //OmsOrderItem orderItem = omsOrderItemDao.findByUuid(orderItemUuid);
        OrderItem orderItem = orderItemDao.findByUuid(orderItemUuid);
       /* orderItems.forEach(orderItem -> {
            OmsOrderItem orderItemUpdate = new OmsOrderItem();
            orderItemUpdate.setEStatus(EStatus.OMS_RECEIVED);
            omsOrderItemDao.updateByUuid(orderItemUpdate, orderItem.getUuid());
        });
       */
        if (EOrderItemState.DELIVERED.name().equals(orderItem.getState().name())) {
            orderItem.signal(EOrderItemAction.USER_CONFIRM_RECEIVED);
            orderItemDao.updateByUuid(orderItem,orderItemUuid);
        }
        OmsOrderItem orderItemUpdate = new OmsOrderItem();
        orderItemUpdate.setEStatus(EStatus.OMS_RECEIVED);
        omsOrderItemDao.updateByUuid(orderItemUpdate, orderItem.getUuid());

        Order order = orderDao.findByUuid(orderItem.getOrderUuid());
        OmsOrder omsOrder = checkByUuid(orderItem.getOrderUuid());
        if (null == omsOrder.getReceivedCount() ) {
            omsOrder.setReceivedCount(0);
        }
        omsOrder.setReceivedCount(omsOrder.getReceivedCount() + 1 );
        order.setReceivedCount(omsOrder.getReceivedCount());

        if(omsOrder.getQuantity().intValue() == omsOrder.getReceivedCount().intValue() ) {
            omsOrder.setReceiveAt(new Date());
            EOmsOrderAction action = EOmsOrderAction.USER_RECEIVED;
            omsOrder.signal(action);
            //更新oms order
            //updateByUuid(omsOrder);
            //更新 order
            order.setReceiveAt(new Date());
            order.signal(EOrderAction.USER_ALL_RECEIVED);
            //orderDao.updateByUuid(order,orderItem.getOrderUuid());
        }

        //更新oms order
        updateByUuid(omsOrder);
        orderDao.updateByUuid(order,orderItem.getOrderUuid());

    }

    @Override
    @Transactional
    public void doRefunded(String orderUuid,String orderItemUuid) {
        orderRefundPostProcessor.orderRefunded(orderUuid,orderItemUuid);
    }
    @Override
    @Transactional
    public void doRefundedByRetailer(String orderUuid,String orderItemUuid){
        OmsOrder omsOrder = omsOrderDao.findByUuid(orderUuid);
        if (EPaymentType.COD.equals(omsOrder.getPaymentType())) {
            return;
        }
        Integer orderRefundedCount = orderRefundDao.getCountByOrderUuidAndState(orderUuid, ERefundState.COMPLETED);
        EOmsOrderAction action = null;
        EOrderAction orderAction = null;
        if (orderRefundedCount.equals(omsOrder.getQuantity())) {
            action = EOmsOrderAction.SYSTEM_CLOSE_BY_ALL_REFUND;
            orderAction = EOrderAction.SYSTEM_CLOSE_BY_ALL_REFUND;
        }

        //更新订单状态
        if (action != null) {
            omsOrder.signal(action);
           /* if (null == omsOrder.getRefundCount()) {
                omsOrder.setRefundCount(0);
            }
            omsOrder.setRefundCount(omsOrder.getRefundCount() + 1);*/
            omsOrderDao.updateByUuid(omsOrder, omsOrder.getUuid());
        }

        if (null != orderAction) {
            Order order = orderDao.findByUuid(orderUuid);
            order.signal(orderAction);
            orderDao.updateByUuid(order, orderUuid);
        }
    }

    @Override
    public void doSettle(Set<String> orderUuids) {

        OmsOrder omsOrder = new OmsOrder();
        omsOrder.signal(EOmsOrderAction.SYSTEM_JOIN_SETTLE);
        baseMapper.updateByUuids(omsOrder, new HashSet<>(orderUuids));
    }

    @Override
    @Transactional
    public void doSettled(Set<String> orderUuids) {

        Set<String> settledOrderUuids = orderUuids.stream()
                .filter(orderUuid -> generalOmsOrderItemService.allInStatus(orderUuid, EStatus.OMS_SETTLED))
                .collect(Collectors.toSet());

        List<OmsOrder> omsOrders = findByUuids(settledOrderUuids);
        omsOrders.forEach(omsOrder -> {
            omsOrder.signal(EOmsOrderAction.SYSTEM_AUTO_SETTLED);
            updateByUuid(omsOrder);
        });
    }

    private void _createOrderItem(String batchNo, Date canShippingAt, Order order, OrderItem orderItem,String defNo) {

        OmsOrderItem omsOrderItem = orderItem.convertToOmsOrderItem();
        omsOrderItem.setCanShippingAt(canShippingAt);
        omsOrderItem.setBatchNo(batchNo);
        omsOrderItem.setNo(OmsNoUtil.genOrderItemNo(batchNo, order.getUuid(), order.getNo()));
        omsOrderItem.setDefNo(defNo);
        omsOrderItem.setEStatus(EStatus.OMS_WAIT_MERCHANT_SHIP);
        omsOrderItemDao.create(omsOrderItem);
    }

    private void _synced(String orderUuid) {
        Order update = new Order();
        update.setSynced(true);
        orderDao.updateByUuid(update, orderUuid);
    }
}
